﻿using com.opencz.utilities;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace ImageReader
{
    public class ImageTool
    {
        public static string StringBitAddition(string StringBit)
        {
            int ZeroLastIndex = StringBit.LastIndexOf('0');
            if (ZeroLastIndex == -1)
            { return "".PadRight(StringBit.Length, '0'); }

            string BeforeZero = StringBit.Substring(0, ZeroLastIndex);
            string AfterZero = StringBit.Substring(ZeroLastIndex + 1);
            StringBit = BeforeZero + "1" + ((ZeroLastIndex + 1) == StringBit.Length ? "" : "".PadRight(AfterZero.Length, '0'));

            return StringBit;
        }

        public static string StringBitAddition(string LatestCode, int bitNum)
        {
            if (LatestCode.Length == bitNum)
            {
                short val = Convert.ToInt16(LatestCode, 2);
                val += 1;
                LatestCode = Convert.ToString(val, 2);
                LatestCode = LatestCode.PadLeft(bitNum, '0');
            }
            else if (LatestCode.Length <= bitNum)
            {
                short val = Convert.ToInt16(LatestCode, 2);
                val += 1;
                LatestCode = Convert.ToString(val, 2) + "0";
                LatestCode = LatestCode.PadLeft(bitNum, '0');
            }
            else
            { throw new Exception("上个码字位数超出了" + bitNum + "位"); }

            return LatestCode;
        }

        public static string StringBitReverse(string StringBit)
        {
            char[] ca = StringBit.ToArray();//.Select(p=>)
            for (int i = 0; i < ca.Length; i++)
            { ca[i] = (ca[i] == '0') ? '1' : '0'; }

            StringBit = new String(ca);
            return StringBit;
        }
    }

    #region JPEG相关数据结构
    public interface ITag
    {
        /// <summary>
        /// 标记代码
        /// </summary>
        string Code { get; set; }
        /// <summary>
        /// 数据长度
        /// </summary>
        int DataLen { get; set; }
    }
    /// <summary>
    /// JPEG文件交换格式
    /// </summary>
    public class JFIF
    {
        /// <summary>
        /// 图像开始（Start of Image）
        /// </summary>
        public ITag SOI { get; set; }
        /// <summary>
        /// 应用程序保留标记0，标记代码0xFFE0
        /// </summary>
        public ITag APP0 { get; set; }
        /// <summary>
        /// 应用程序保留标记集合，其中n=1～15(任选)，标记代码0xFFE1~0xFFF
        /// </summary>
        public List<ITag> APPNS { get; set; }
        /// <summary>
        /// 定义量化表（Define Quantization Table）,标记代码0xFFDB。
        /// 量化表可能以多个DQT，每个DQT 中一个表项，或者一个DQT中包含多个表项。
        /// 此结构中统一采用后一种方式。
        /// </summary>
        public ITag DQT { get; set; }
        /// <summary>
        /// 图像帧开始（Start of Frame），标记代码0xFF C0-CF；
        /// 非层次哈夫曼编码>>
        /// FFC0:基线离散余弦变换；
        /// FFC1:扩展顺序离散余弦变换；
        /// FFC2:递进离散余弦变换；
        /// FFC3:空间顺序无损；
        /// 层次哈夫曼编码>>
        /// FFC5:差分离散余弦变换；
        /// FFC6:差分层次离散余弦变换；
        /// FFC7:差分空间无损；
        /// 非层次算术编码>>
        /// FFC9:为JPEG扩展保留；
        /// FFCA:扩展顺序离散余弦变换；
        /// FFCB:递进离散余弦变换；
        /// 层次算术编码>>
        /// FCD:空间顺序无损；
        /// FFCE:差分层次离散余弦变换；
        /// FFCF:差分空间无损；
        /// </summary>
        public ITag SOFN { get; set; }
        /// <summary>
        /// 定义哈夫曼表（Difine Huffman Table）,标记代码0xFFC4
        /// </summary>
        public ITag DHT { get; set; }
        /// <summary>
        /// 定义差分编码累计复位的间隔（Define Restart Interval）,标记代码0xFFDD
        /// </summary>
        public ITag DRI { get; set; }
        /// <summary>
        /// 扫描开始（Start of Scan）,12字节,标记代码0xFFC4
        /// </summary>
        public ITag SOS { get; set; }
        /// <summary>
        /// 注释，标记代码0xFFFE
        /// </summary>
        public ITag COM { get; set; }
    }
    /// <summary>
    /// 图像密度单位
    /// </summary>
    public enum DensityUnits
    {
        /// <summary>
        /// 无
        /// </summary>
        None,
        /// <summary>
        /// 点每英寸
        /// </summary>
        DPI,
        /// <summary>
        /// 点每厘米
        /// </summary>
        DPC
    }
    /// <summary>
    /// 颜色分量类型
    /// </summary>
    public enum ColorComponentTypes
    {
        /// <summary>
        /// 灰度图
        /// </summary>
        Gray,
        /// <summary>
        /// YCrCb或YIQ
        /// </summary>
        YCrCb_YIQ,
        /// <summary>
        /// CMYK
        /// </summary>
        CMYK,
    }
    /// <summary>
    /// 哈夫曼表类型
    /// </summary>
    public enum HuffmanTableTypes
    {
        DC直流,
        AC交流
    }
    /// <summary>
    /// 图像开始（Start of Image）
    /// </summary>
    public class SOI : ITag
    {
        /// <summary>
        /// 标记代码0xFFD8
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 数据长度
        /// </summary>
        public int DataLen { get; set; }
    }
    /// <summary>
    /// 应用程序保留标记0，标记代码0xFFE0
    /// </summary>
    public class APP0 : ITag
    {
        /// <summary>
        /// 标记代码0xFFE0
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// APP0数据长度
        /// </summary>
        public int DataLen { get; set; }
        /// <summary>
        /// "JFIF"+"0"，识别APP0标记
        /// </summary>
        public string JFIFn { get; set; }
        /// <summary>
        /// 主版本号
        /// </summary>
        public int MainVer { get; set; }
        /// <summary>
        /// 次版本号
        /// </summary>
        public int SubVer { get; set; }
        /// <summary>
        /// 图像密度单位
        /// </summary>
        public DensityUnits DensityUnit { get; set; }
        /// <summary>
        /// //水平方向图元密度
        /// </summary>
        public int XDensity { get; set; }
        /// <summary>
        /// //垂直方向图元密度
        /// </summary>
        public int YDensity { get; set; }
        /// <summary>
        /// 缩略图水平像素
        /// </summary>
        public int ThumbXpixel { get; set; }
        /// <summary>
        /// 缩略图垂直像素
        /// </summary>
        public int ThumbYpixel { get; set; }
        /// <summary>
        /// 缩略图数据
        /// </summary>
        public byte[] ThumbData { get; set; }
    }
    /// <summary>
    /// 应用程序保留标记n，其中n=1～15(任选)，标记代码0xFFE1~0xFFF
    /// </summary>
    public class APPN : ITag
    {
        /// <summary>
        /// 标记代码0xFFE0
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 编号，范围1-15
        /// </summary>
        public int Num { get; set; }
        /// <summary>
        /// APP0数据长度
        /// </summary>
        public int DataLen { get; set; }
        /// <summary>
        /// APPN数据
        /// </summary>
        public byte[] APPNData { get; set; }
    }
    /// <summary>
    /// 定义量化表（Define Quantization Table）,标记代码0xFFDB。
    /// 量化表可能以多个DQT，每个DQT 中一个表项，或者一个DQT中包含多个表项。
    /// 此结构中统一采用后一种方式。
    /// </summary>
    public class DQT : ITag
    {
        /// <summary>
        /// 标记代码0xFFE0
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// APP0数据长度
        /// </summary>
        public int DataLen { get; set; }
        /// <summary>
        /// 表项集合,量化数量为1~4,量化表可能以多个DQT，每个DQT 中一个表项，或者一个DQT中包含多个表项
        /// </summary>
        public List<DQTItem> DQTItems { get; set; }
        /// <summary>
        /// 表项
        /// </summary>
        public class DQTItem
        {
            public int TableID { get; set; }
            /// <summary>
            /// 量化精度
            /// </summary>
            public int QuantizationAccuracy { get; set; }
            /// <summary>
            /// 表项长度,(64×(精度+1))字节
            /// </summary>
            public int TableItemLen { get; set; }
            /// <summary>
            /// 表项数据
            /// </summary>
            public byte[] TableItemData { get; set; }
        }
    }
    /// <summary>
    /// 图像帧开始（Start of Frame），标记代码0xFFC0
    /// 非层次哈夫曼编码>>
    /// FFC0:基线离散余弦变换；
    /// FFC1:扩展顺序离散余弦变换；
    /// FFC2:递进离散余弦变换；
    /// FFC3:空间顺序无损；
    /// 层次哈夫曼编码>>
    /// FFC5:差分离散余弦变换；
    /// FFC6:差分层次离散余弦变换；
    /// FFC7:差分空间无损；
    /// 非层次算术编码>>
    /// FFC9:为JPEG扩展保留；
    /// FFCA:扩展顺序离散余弦变换；
    /// FFCB:递进离散余弦变换；
    /// 层次算术编码>>
    /// FCD:空间顺序无损；
    /// FFCE:差分层次离散余弦变换；
    /// FFCF:差分空间无损； 
    /// </summary>
    public class SOFN : ITag
    {
        /// <summary>
        /// 标记代码0xFFE0
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 数据长度
        /// </summary>
        public int DataLen { get; set; }
        /// <summary>
        /// 精度
        /// </summary>
        public int Accuracy { get; set; }
        /// <summary>
        /// 图像高度
        /// </summary>
        public int ImageHeight { get; set; }
        /// <summary>
        /// 图像宽度
        /// </summary>
        public int ImageWidth { get; set; }
        /// <summary>
        /// 颜色分量
        /// </summary>
        public ColorComponentTypes ColorComponentType { get; set; }
        /// <summary>
        /// 颜色分量信息集合
        /// </summary>
        public List<ComponentItem> ComponentItems { get; set; }
        /// <summary>
        /// 分量信息
        /// </summary>
        public class ComponentItem
        {
            /// <summary>
            /// 颜色分量ID
            /// </summary>
            public int ID { get; set; }
            /// <summary>
            /// 水平采样因子
            /// </summary>
            public int HExamplingRatio { get; set; }
            /// <summary>
            /// 垂直采样因子
            /// </summary>
            public int VExamplingRatio { get; set; }
            /// <summary>
            /// 量化表数据
            /// </summary>
            public int QuantizationTableID { get; set; }
        }
    }
    /// <summary>
    /// 定义哈夫曼表（Difine Huffman Table）,标记代码0xFFC4
    /// </summary>
    public class DHT : ITag
    {
        /// <summary>
        /// 标记代码0xFFC4
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 数据长度
        /// </summary>
        public int DataLen { get; set; }
        /// <summary>
        /// 直流哈夫曼表0
        /// </summary>
        public DHTItem DHT_DC0 { get; set; }
        /// <summary>
        /// 直流哈夫曼表1
        /// </summary>
        public DHTItem DHT_DC1 { get; set; }
        /// <summary>
        /// 交流哈夫曼表0
        /// </summary>
        public DHTItem DHT_AC0 { get; set; }
        /// <summary>
        /// 交流哈夫曼表1
        /// </summary>
        public DHTItem DHT_AC1 { get; set; }

        public List<DHTItem> DCTables { get; set; }

        public List<DHTItem> ACTables { get; set; }

        public class DHTItem
        {
            /// <summary>
            /// 哈夫曼表ID
            /// </summary>
            public int TableID { get; set; }
            /// <summary>
            /// 哈夫曼表类型
            /// </summary>
            public HuffmanTableTypes HuffmanTableType { get; set; }
            /// <summary>
            /// 不同位数的码字数量,16字节
            /// </summary>
            public byte[] HuffmanChainCodes { get; set; }

            private List<string> _GetHuffmanTree;
            /// <summary>
            /// 哈夫曼树
            /// </summary>
            public List<string> HuffmanTree
            {
                get
                {
                    if (HuffmanChainCodes != null && (_GetHuffmanTree == null) || _GetHuffmanTree.Count == 0)
                    {
                        _GetHuffmanTree = new List<string>();
                        string[] HuffmanChainCodesStrList = BitConverter.ToString(HuffmanChainCodes).Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
                        string LatestCode = "";
                        int LatestLen = 0;
                        int LatestVal = 0;
                        for (int i = 1; i <= HuffmanChainCodesStrList.Length; i++)
                        {
                            int len = Convert.ToUInt16(HuffmanChainCodesStrList[i - 1], 16);
                            if (len > 0)
                            {
                                LatestLen = LatestLen == 0 ? i : LatestLen;
                                for (int j = 0; j < len; j++)
                                {
                                    string hfcode = "";
                                    if (LatestCode == "")
                                    { hfcode = "".PadRight(i, '0'); }
                                    else
                                    {
                                        LatestVal = Convert.ToUInt16(LatestCode, 2);
                                        LatestVal += 1;
                                        hfcode = Convert.ToString(LatestVal, 2).PadLeft(LatestLen, '0').PadRight(i, '0');
                                        LatestLen = i;
                                    }
                                    LatestCode = hfcode;
                                    _GetHuffmanTree.Add(hfcode);
                                }
                            }
                        }
                    }

                    return _GetHuffmanTree;
                }
            }


            public Dictionary<long, int> _HuffmanTreeDic { get; set; }
            public Dictionary<long, int> HuffmanTreeDic
            {
                get
                {
                    if (_HuffmanTreeDic == null)
                    {
                        if (this.HuffmanTree != null)
                        {
                            this._HuffmanTreeDic = this.HuffmanTree.ToDictionary(p => long.Parse(p), q => this.HuffmanTree.IndexOf(q));
                        }
                    }

                    return this._HuffmanTreeDic;
                }
            }
            /// <summary>
            /// 哈夫曼编码总数
            /// </summary>
            public int HuffmanChainNum { get; set; }
            /// <summary>
            /// 各哈夫曼编码权重从小到大排列
            /// </summary>
            public byte[] HuffmanNodeWeight { get; set; }
        }
    }
    /// <summary>
    /// 定义差分编码累计复位的间隔（Define Restart Interval）,标记代码0xFFDD
    /// </summary>
    public class DRI : ITag
    {
        /// <summary>
        /// 标记代码0xFFC4
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 数据长度
        /// </summary>
        public int DataLen { get; set; }
        /// <summary>
        /// MCU,Minimum Coded Unit 最小编码单元;
        /// MCU块的单元中的重新开始间隔;
        /// 设其值为n，则表示每n个MCU块就有一个，RSTn标记。第一个标记是RST0，第二个是，RST1等，RST7后再从RST0重复;
        /// 如果没有本标记段，或间隔值为0时，就表示不存在重开始间隔和标记RST;
        /// </summary>
        public int RSTInterval { get; set; }
    }
    /// <summary>
    /// 扫描开始（Start of Scan）,12字节,标记代码0xFFC4
    /// </summary>
    public class SOS : ITag
    {
        /// <summary>
        /// 标记代码0xFFC4
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 数据长度
        /// </summary>
        public int DataLen { get; set; }
        /// <summary>
        /// 颜色分量类型
        /// </summary>
        public ColorComponentTypes ColorComponentType { get; set; }

        public List<SOSColorComponentItem> SOSColorComponents { get; set; }
        /// <summary>
        /// 谱选择开始
        /// </summary>
        public int PSelectStart { get; set; }
        /// <summary>
        /// 谱选择结束
        /// </summary>
        public int PSelectEnd { get; set; }
        /// <summary>
        /// 谱选择
        /// </summary>
        public int PSelect { get; set; }
        /// <summary>
        /// 第一个MCU字节，在文件流中的位置
        /// </summary>
        public long MCUDataStartFilePosition { get; set; }
        /// <summary>
        /// 颜色分量信息
        /// </summary>
        public class SOSColorComponentItem
        {
            /// <summary>
            /// 颜色分量ID
            /// </summary>
            public int ColorComponentID { get; set; }
            /// <summary>
            /// 直流系数表号 
            /// </summary>
            public int DCTableID { get; set; }
            /// <summary>
            /// 交流系数表号 
            /// </summary>
            public int ACTableID { get; set; }
        }
    }
    /// <summary>
    /// 注释，标记代码0xFFFE
    /// </summary>
    public class COM : ITag
    {
        /// <summary>
        /// 标记代码0xFFC4
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 数据长度
        /// </summary>
        public int DataLen { get; set; }
        /// <summary>
        /// 注释内容
        /// </summary>
        public string Content { get; set; }
    }
    #endregion

    /// <summary>
    /// 序列式离散余弦JPEG解码；JPEG2000不再使用8×8像素分块和离散余弦变换对图像进行处理，而采用了对图像进行不同分辨率金字塔形的存贮。
    /// </summary>
    public class JpegReader
    {
        public bool ShowY { get; set; }
        public bool ShowCr { get; set; }
        public bool ShowCb { get; set; }

        private bool APPNSkep { get; set; }

        /// <summary>
        /// 是否关闭Log
        /// </summary>
        public bool LogOff { get; set; }
        JFIF jfif;
        SOFN sof = null;
        DQT dqt = null;
        DHT dht = null;
        SOS sos = null;
        /// <summary>
        /// 如果sof，dqt，dht，sos任何一项为空，则尝试回到缩略图中获取，但不解析缩略图数据
        /// </summary>
        bool RebackReadTag { get; set; }
        public StringBuilder LogSb { get; set; }
        public FileStream FS = null;
        public Rectangle ShowClip { get; set; }
        int MCUIDX { get; set; }

        public JpegReader(string file, StringBuilder log)
        {
            FS = new FileStream(file, FileMode.Open);
            if (log == null)
            { this.LogOff = true; }
            else
            { this.LogSb = log; }

            this.jfif = GetImageInfo();
        }

        public void Release()
        { if (this.FS != null) { FS.Close(); FS.Dispose(); } }

        public JFIF JFIF
        {
            get
            {
                if (this.jfif.SOI != null && string.IsNullOrEmpty(this.jfif.SOI.Code))
                { this.jfif = this.GetImageInfo(); }

                return this.jfif;
            }
        }

        public JFIF GetJFIF()
        {
            if (this.jfif.SOI != null && string.IsNullOrEmpty(this.jfif.SOI.Code))
            { this.jfif = this.GetImageInfo(); }
            this.Release();

            return this.jfif;
        }

        /// <summary>
        /// 解析JPEG文件头
        /// </summary>
        /// <returns></returns>
        private JFIF GetImageInfo()
        {
            JFIF jfif = new JFIF();
            jfif.APPNS = new List<ITag>();

            try
            {
                byte[] buf = new byte[2];
                while (true)
                {
                    byte rd = (byte)FS.ReadByte();
                    if (rd != 255)
                    { continue; }
                    if (rd == 255)
                    {
                        buf[0] = 255;
                        while (true)
                        {
                            rd = (byte)FS.ReadByte();
                            if (rd != 255)
                            { break; }
                        }
                        buf[1] = rd;
                    }

                    //byte[] buf = new byte[2];
                    //int rc = FS.Read(buf, 0, buf.Length);
                    string code = HexUtil.ToHex(buf);

                    switch (code)
                    {
                        //非层次哈夫曼编码
                        case "FFC0"://基线离散余弦变换
                        case "FFC1"://扩展顺序离散余弦变换
                        case "FFC2"://递进离散余弦变换
                        case "FFC3"://空间顺序无损
                                    //层次哈夫曼编码
                        case "FFC5"://差分离散余弦变换
                        case "FFC6"://差分层次离散余弦变换
                        case "FFC7"://差分空间无损
                                    //非层次算术编码
                        case "FFC9"://为JPEG扩展保留
                        case "FFCA"://扩展顺序离散余弦变换
                        case "FFCB"://递进离散余弦变换
                                    //层次算术编码
                        case "FFCD"://空间顺序无损
                        case "FFCE"://差分层次离散余弦变换
                        case "FFCF"://差分空间无损
                            jfif.SOFN = this.SOFN(FS, buf);
                            break;
                        case "FFC8":
                            // M_JPG   = 0xc8,
                            break;
                        case "FFC4":
                            jfif.DHT = this.DHT(FS);
                            break;
                        case "FFCC":
                            //M_DAC   = 0xcc,
                            break;

                        case "FFD8":
                            jfif.SOI = this.SOI(FS, buf);
                            break;
                        case "FFE0":
                            jfif.APP0 = this.APP0(FS, buf);
                            break;
                        case "FFE1":
                        case "FFE2":
                        case "FFE3":
                        case "FFE4":
                        case "FFE5":
                        case "FFE6":
                        case "FFE7":
                        case "FFE8":
                        case "FFE9":
                        case "FFEA":
                        case "FFEB":
                        case "FFEC":
                        case "FFED":
                        case "FFEE":
                        case "FFEF":
                            jfif.APPNS.Add(this.APPN(FS, buf));
                            break;
                        case "FFDB":
                            jfif.DQT = this.DQT(FS);
                            break;
                        case "FFDD":
                            jfif.DRI = this.DRI(FS, buf);
                            break;
                        case "FFFE":
                            jfif.COM = this.COM(FS);
                            break;
                        case "FFDA":
                            jfif.SOS = this.SOS(FS, buf);
                            sof = (SOFN)jfif.SOFN;
                            dqt = (DQT)jfif.DQT;
                            dht = (DHT)jfif.DHT;
                            sos = (SOS)jfif.SOS;
                            return jfif;
                        default: return jfif;
                    }
                }
            }
            catch (Exception ex)
            {
                this.Release();
                throw new Exception(ex.Message + Environment.NewLine + ex.StackTrace);
            }
            //return jfif;
        }

        #region [基础标记解析]
        /// <summary>
        /// SOI,标记代码0xFFD8
        /// </summary>
        /// <param name="fs"></param>
        /// <param name="buf"></param>
        /// <param name="sb"></param>
        public ITag SOI(FileStream fs, byte[] buf)
        {
            SOI s = new ImageReader.SOI();
            string SOI = HexUtil.ToHex(buf);
            s.Code = SOI;
            return s;
        }
        /// <summary>
        /// 应用程序保留标记0,标记代码0xFFE0
        /// </summary>
        /// <param name="fs"></param>
        /// <param name="buf"></param>
        /// <param name="sb"></param>
        public ITag APP0(FileStream fs, byte[] buf)
        {
            APP0 a = new ImageReader.APP0();
            //JFIF application segment
            string app0 = HexUtil.ToHex(buf);
            a.Code = app0;
            // APP0数据长度
            buf = new byte[2];
            int rc = fs.Read(buf, 0, buf.Length);
            buf = buf.Reverse().ToArray();
            int app0len = BitConverter.ToUInt16(buf, 0);
            a.DataLen = app0len;
            // "JFIF"+"0"  识别APP0标记
            buf = new byte[5];
            rc = fs.Read(buf, 0, buf.Length);
            string idapp0 = Encoding.ASCII.GetString(buf, 0, 4) + Convert.ToUInt16(buf[4]);
            a.JFIFn = idapp0;
            //主要版本号
            buf = new byte[1];
            rc = fs.Read(buf, 0, buf.Length);
            int mainver = Convert.ToUInt16(buf[0]);
            a.MainVer = mainver;
            //次要版本号
            buf = new byte[1];
            rc = fs.Read(buf, 0, buf.Length);
            int subver = Convert.ToUInt16(buf[0]);
            a.SubVer = subver;
            //X和Y的密度单位
            buf = new byte[1];
            rc = fs.Read(buf, 0, buf.Length);
            int densityUnit = Convert.ToUInt16(buf[0]);
            a.DensityUnit = densityUnit == 0 ? DensityUnits.None : densityUnit == 1 ? DensityUnits.DPI : (densityUnit == 2 ? DensityUnits.DPC : DensityUnits.None);
            //水平方向图元密度
            buf = new byte[2];
            rc = fs.Read(buf, 0, buf.Length);
            buf = buf.Reverse().ToArray();
            int xdensity = BitConverter.ToUInt16(buf, 0);
            a.XDensity = xdensity;
            //垂直方向图元密度
            buf = new byte[2];
            rc = fs.Read(buf, 0, buf.Length);
            buf = buf.Reverse().ToArray();
            int ydensity = BitConverter.ToUInt16(buf, 0);
            a.YDensity = ydensity;
            //缩略图水平像素数目
            buf = new byte[1];
            rc = fs.Read(buf, 0, buf.Length);
            int thumbxpixel = Convert.ToUInt16(buf[0]);
            a.ThumbXpixel = thumbxpixel;
            //缩略图垂直像素数目
            buf = new byte[1];
            rc = fs.Read(buf, 0, buf.Length);
            int thumbypixel = Convert.ToUInt16(buf[0]);
            a.ThumbYpixel = thumbypixel;
            //如果有缩略图下面的thumbxpixel * thumbypixel * 3字节就是缩略图数据
            if (thumbxpixel > 0)
            {
                buf = new byte[thumbxpixel * thumbypixel * 3];
                rc = fs.Read(buf, 0, buf.Length);
                a.ThumbData = buf;
            }

            return a;
        }


        #region [APPN]
        /// <summary>
        /// 应用程序保留标记n,标记代码0xFFE1~0xFFF。
        /// 据观察：有APPN标签的图像具有两个0xFFD8标签，第二个0xFFD8标签才是真正的图像数据
        /// </summary>
        /// <param name="fs"></param>
        /// <param name="buf"></param>
        /// <param name="sb"></param>
        public ITag APPN(FileStream fs, byte[] buf)
        {
            APPN a = new ImageReader.APPN();
            if (buf[0] == 255 && buf[1] >= 224 && buf[1] <= 239)
            {
                string appnCode = HexUtil.ToHex(buf);
                a.Code = appnCode;
                a.Num = buf[1] - 0xE0;
                //appn 数据长度
                buf = new byte[2];
                int rc = fs.Read(buf, 0, buf.Length);
                buf = buf.Reverse().ToArray();
                int appnDataLen = BitConverter.ToUInt16(buf, 0);
                a.DataLen = appnDataLen;

                if (a.Num == 1)
                { ReadExif_APP1(fs); }
                else
                {
                    buf = new byte[appnDataLen - 2];
                    rc = fs.Read(buf, 0, buf.Length);
                }
            }
            else
            { fs.Seek(-2, SeekOrigin.Current); }
            return a;
        }

        string[] DataFormat = new string[] { "unsigned byte", "ascii string", "unsigned short", "unsigned long", "unsigned rational", "signed byte"
                    , "undefined", "signed short", "signed long", "signed rational", "single float", "double float"};
        int[] DataLen = new int[] { 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };

        string[] IFD0TagNameEn = new string[] { "ImageDescription", "Cammera Maker", "Model", "Orientation", "XResolution", "YResolution", "ResolutionUnit", "Software"
            , "DateTime", "WhitePoint", "PrimaryChromaticitie", "YCbCrCoefficients", "YCbCrPositioning", "ReferenceBlackWhite", "Copyright", "ExifOffset" };
        string[] IFD0TagNameCn = new string[] { "描述", "制造商", "相机模块代码", "相机于场景方向", "水平显示/打印分辨率", "垂直显示/打印分辨率", "分辨率单位", "相机固件"
            , "修改日期", "白点色度", "原始色度", "YCbCr系数", "像素阵列色度采样点", "黑/白点参考值", "版权", "子IFD的偏移量" };
        List<int> IFD0TagNum = new List<int>() { 0x010E, 0x010F, 0x0110, 0x0112, 0x011A, 0x011B, 0x0128, 0x0131, 0x0132, 0x013E, 0x013F, 0x0211, 0x0213, 0x0214, 0x8298, 0x8769 };
        string[] IFD0TagItemType = new string[] { "ascii string", "ascii string", "ascii string", "unsigned short", "unsigned rational", "unsigned rational", "unsigned short"
            , "ascii string", "ascii string", "unsigned rational", "unsigned rational", "unsigned rational", "unsigned short", "unsigned rational", "ascii string", "unsigned long" };
        int[] IFD0TagItemLen = new int[] { 0, 0, 0, 1, 1, 1, 1, 0, 20, 2, 6, 3, 1, 6, 0, 1 };

        string[] IFD1TagNameEn = new string[] { "ImageWidth", "ImageLength", "BitsPerSample", "Compression", "PhotometricInterpretation", "StripOffsets", "SamplesPerPixel", "RowsPerStrip"
            , "StripByteConunts", "XResolution", "YResolution", "PlanarConfiguration", "ResolutionUnit", "JpegIFOffset", "JpegIFByteCount", "YCbCrCoefficients"
            , "YCbCrSubSampling", "YCbCrPositioning", "ReferenceBlackWhite" };
        string[] IFD1TagNameCn = new string[] { "缩略图宽度", "缩略图高度", "像素比特位","压缩方式", "色彩空间", "图像数据偏移量", "每像素组件数","每数据带行数"
            ,"每数据带字节数", "缩略图X显示/打印分辨率", "缩略图Y显示/打印分辨率", "YCbCr存储方式", "分辨率单位", "到JPEG数据的偏移", "JPEG图像数据大小", "YCbCr转RGB系数"
            , "YCbCr子采样色度数", "YCbCr子采样色度采样点", "黑点/白点参考值" };
        List<int> IFD1TagNum = new List<int>() { 0x0100, 0x0101, 0x0102, 0x0103, 0x0106, 0x0111, 0x0115, 0x0116, 0x0117, 0x011a, 0x011b, 0x011c, 0x0128, 0x0201, 0x0202, 0x0211, 0x0212, 0x0213, 0x0214 };
        string[] IFD1TagItemType = new string[] { "unsigned short/long", "unsigned short/long", "unsigned short", "unsigned short", "unsigned short", "unsigned short/long", "unsigned short", "unsigned short/long"
            , "unsigned short/long", "unsigned rational", "unsigned rational", "unsigned short", "unsigned short", "unsigned long", "unsigned long", "unsigned rational"
            , "unsigned short", "unsigned short", "unsigned rational" };
        int[] IFD1TagItemLen = new int[] { 1, 1, 3, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 3, 2, 1, 6 };

        long ThumbImgOffset { get; set; }
        long ThumbImgBytesLen { get; set; }
        long APP1Pos = 0;
        public void ReadExif_APP1(FileStream fs)
        {
            List<string> TagNoteList = new List<string>();
            byte[] buf = new byte[6];
            int rc = fs.Read(buf, 0, buf.Length);
            string exifH = Encoding.ASCII.GetString(buf);
            APP1Pos = fs.Position;
            if (exifH.ToLower().StartsWith("exif"))
            {
                //Tiff头
                buf = new byte[2];
                rc = fs.Read(buf, 0, buf.Length);
                //Motorola Intel
                bool IsIntel = false;
                if (buf[0] == 0x49)
                { IsIntel = true; }
                else if (buf[0] == 0x4D)
                { IsIntel = false; }
                //版本（固定值：0x0042）
                buf = new byte[2];
                rc = fs.Read(buf, 0, buf.Length);
                //到第一个 IFD0(Image File Directory)的偏移量.从TIFF头("II" 或者 "MM")开始, 包含自己偏移量值的本身, 到下一个IFD为止的 长度的字节数. 
                //通常地第一个 IFD 是紧挨着 TIFF 头出现的, 因此这个偏移量的值是 '0x00000008'.
                //地址偏移
                buf = new byte[4];
                rc = fs.Read(buf, 0, buf.Length);
                buf = IsIntel ? buf : buf.Reverse().ToArray();
                int FirstIFDOff = BitConverter.ToInt32(buf, 0);
                //IFD0 目录
                int NextIFDOff = ReadIFDs(fs, 0, TagNoteList, APP1Pos, FirstIFDOff, IsIntel);
                while (NextIFDOff > 0)
                {
                    NextIFDOff = ReadIFDs(fs, 1, TagNoteList, APP1Pos, NextIFDOff, IsIntel);
                }
                if (this.ThumbImgOffset > 0 && this.ThumbImgBytesLen > 0)
                { fs.Seek(APP1Pos + this.ThumbImgOffset + this.ThumbImgBytesLen, SeekOrigin.Begin); }
            }
        }

        int ReadIFDs(FileStream fs, int IFDIdx, List<string> TagNoteList, long IFD0Pos, long StartOff, bool IsIntel)
        {
            //开始地址
            fs.Seek(IFD0Pos + StartOff, SeekOrigin.Begin);
            //表项项数量
            byte[] buf = new byte[2];
            int rc = fs.Read(buf, 0, buf.Length);
            buf = IsIntel ? buf : buf.Reverse().ToArray();
            int DirCnt = BitConverter.ToUInt16(buf, 0);

            string[] IFDTagNameEn = (IFDIdx == 0 ? IFD0TagNameEn : IFD1TagNameEn);
            string[] IFDTagNameCn = (IFDIdx == 0 ? IFD0TagNameCn : IFD1TagNameCn);
            List<int> IFDTagNum = (IFDIdx == 0 ? IFD0TagNum : IFD1TagNum);
            string[] IFDTagItemType = (IFDIdx == 0 ? IFD0TagItemType : IFD1TagItemType);
            int[] IFDTagItemLen = (IFDIdx == 0 ? IFD0TagItemLen : IFD1TagItemLen);
            //每个表项12字节
            for (int i = 0; i < DirCnt; i++)
            {
                //标记码（公用标记码大于2545小于321的标记码，大于0x8000的码是私有码，可以用于各个公司专用的程序读取）
                buf = new byte[2];
                rc = fs.Read(buf, 0, buf.Length);
                buf = IsIntel ? buf : buf.Reverse().ToArray();
                int TagVal = BitConverter.ToUInt16(buf, 0);
                if (TagVal > 0x8000)//大于0x8000的码是私有标记码
                { }
                int TagIdx = IFDTagNum.IndexOf(TagVal);
                //数据类型
                buf = new byte[2];
                rc = fs.Read(buf, 0, buf.Length);
                buf = IsIntel ? buf : buf.Reverse().ToArray();
                int FormatIdx = BitConverter.ToUInt16(buf, 0) - 1;
                string FormatName = DataFormat[FormatIdx];
                //长度字段
                buf = new byte[4];
                rc = fs.Read(buf, 0, buf.Length);
                buf = IsIntel ? buf : buf.Reverse().ToArray();
                int Len = BitConverter.ToInt32(buf, 0);
                int BytesLen = DataLen[FormatIdx] * Len;
                //数据指针或数据字段
                buf = new byte[4];
                rc = fs.Read(buf, 0, buf.Length);
                if (BytesLen <= 4)//下面的4字节为数据字段
                {
                    if (TagIdx >= 0)
                    {
                        string IFDxTypeName = IFDTagItemType[TagIdx];
                        if (TagVal == 0x8769)//子IFD
                        { }
                        else
                        {
                            if (IFDTagNameEn[TagIdx] == "Orientation")
                            {
                                string OrientationStrVal = GetTagItemValue(IsIntel, IFDxTypeName, 1, buf).ToString();
                                int OrientationVal = int.Parse(OrientationStrVal);
                                string OrientationNote = "";
                                if (OrientationVal == 0 || OrientationVal == 1)
                                { OrientationNote = "图像不需要旋转"; }
                                else if (OrientationVal == 2)
                                { OrientationNote = "图像需要沿Y轴旋转180度"; }
                                else if (OrientationVal == 3)
                                { OrientationNote = "图像需要沿X、Y各轴旋转180度"; }
                                else if (OrientationVal == 4)
                                { OrientationNote = "图像需要沿X轴旋转180度"; }
                                else if (OrientationVal == 5)
                                { OrientationNote = "图像需要沿X轴旋转180度、中点顺时针旋转90度"; }
                                else if (OrientationVal == 6)
                                { OrientationNote = "图像需要沿中点逆时针旋转90度"; }
                                else if (OrientationVal == 7)
                                { OrientationNote = "图像需要沿X轴旋转180度、中点逆时针旋转90度"; }
                                else if (OrientationVal == 8)
                                { OrientationNote = "图像需要中点顺时针旋转90度"; }
                                string TagNote = "Exif" + IFDIdx + "：" + IFDTagNameCn[TagIdx] + ":" + OrientationVal + "," + OrientationNote;
                                TagNoteList.Add(TagNote);
                            }
                            else if (IFDTagNameEn[TagIdx] == "ResolutionUnit")
                            {
                                string ResolutionUnitStrVal = GetTagItemValue(IsIntel, IFDxTypeName, 1, buf).ToString();
                                int ResolutionUnitVal = int.Parse(ResolutionUnitStrVal);
                                string ResolutionUnitNote = "";
                                if (ResolutionUnitVal == 0 || ResolutionUnitVal == 1)
                                { ResolutionUnitNote = "无"; }
                                else if (ResolutionUnitVal == 2)
                                { ResolutionUnitNote = "英寸"; }
                                else if (ResolutionUnitVal == 3)
                                { ResolutionUnitNote = "厘米"; }
                                string TagNote = "Exif" + IFDIdx + "：" + IFDTagNameCn[TagIdx] + ":" + ResolutionUnitVal + "," + ResolutionUnitNote;
                            }
                            else if (IFDTagNameEn[TagIdx] == "Compression")
                            {
                                string CompressionStrVal = GetTagItemValue(IsIntel, IFDxTypeName, 1, buf).ToString();
                                int CompressionVal = int.Parse(CompressionStrVal);
                                string CompressionNote = "";
                                if (CompressionVal == 1)
                                { CompressionNote = "无压缩"; }
                                else if (CompressionVal == 6)
                                { CompressionNote = "JPEG压缩"; }
                                string TagNote = "Exif" + IFDIdx + "：" + IFDTagNameCn[TagIdx] + ":" + CompressionVal + "," + CompressionNote;
                                TagNoteList.Add(TagNote);
                            }
                            else if (IFDTagNameEn[TagIdx] == "YCbCrPositioning")
                            {
                                string YCbCrPositioningStrVal = GetTagItemValue(IsIntel, IFDxTypeName, 1, buf).ToString();
                                int YCbCrPositioningVal = int.Parse(YCbCrPositioningStrVal);
                                string YCbCrPositioningNote = "";
                                if (YCbCrPositioningVal == 1)
                                { YCbCrPositioningNote = "采样像素阵列的色度采样点为像素阵列的中心"; }
                                else if (YCbCrPositioningVal == 2)
                                { YCbCrPositioningNote = "采样像素阵列的色度采样点为基准点"; }
                                string TagNote = "Exif" + IFDIdx + "：" + IFDTagNameCn[TagIdx] + ":" + YCbCrPositioningVal + "," + YCbCrPositioningNote;
                                TagNoteList.Add(TagNote);
                            }
                            else if (IFDTagNameEn[TagIdx] == "JpegIFOffset")
                            {
                                string JpegIFOffsetStrVal = GetTagItemValue(IsIntel, IFDxTypeName, 1, buf).ToString();
                                long JpegIFOffsetVal = long.Parse(JpegIFOffsetStrVal);
                                this.ThumbImgOffset = JpegIFOffsetVal;

                                string TagNote = "Exif" + IFDIdx + "：" + IFDTagNameCn[TagIdx] + ":" + JpegIFOffsetVal;
                                TagNoteList.Add(TagNote);
                            }
                            else if (IFDTagNameEn[TagIdx] == "JpegIFByteCount")
                            {
                                string JpegIFByteCountStrVal = GetTagItemValue(IsIntel, IFDxTypeName, 1, buf).ToString();
                                long JpegIFByteCountVal = long.Parse(JpegIFByteCountStrVal);
                                this.ThumbImgBytesLen = JpegIFByteCountVal;

                                string TagNote = "Exif" + IFDIdx + "：" + IFDTagNameCn[TagIdx] + ":" + ThumbImgBytesLen;
                                TagNoteList.Add(TagNote);
                            }
                            else
                            {
                                string TagNote = "Exif" + IFDIdx + "：" + IFDTagNameCn[TagIdx] + ":" + GetTagItemValue(IsIntel, IFDxTypeName, 1, buf);
                                TagNoteList.Add(TagNote);
                            }
                        }
                    }
                }
                else//下面的4字节为数据指针
                {
                    long tpos = fs.Position;
                    buf = IsIntel ? buf : buf.Reverse().ToArray();
                    int offset = BitConverter.ToInt32(buf, 0);
                    fs.Seek(IFD0Pos + offset, SeekOrigin.Begin);
                    buf = new byte[BytesLen];
                    rc = fs.Read(buf, 0, buf.Length);

                    if (TagIdx >= 0)
                    {
                        string IFDxTypeName = IFDTagItemType[TagIdx];
                        string typeName = IFDTagItemType[TagIdx];
                        int typeLen = IFDTagItemLen[TagIdx];
                        string TagNote = "Exif" + IFDIdx + "：" + IFDTagNameCn[TagIdx] + ":" + GetTagItemValue(IsIntel, IFDxTypeName, typeLen, buf);
                        TagNoteList.Add(TagNote);
                    }

                    fs.Seek(tpos, SeekOrigin.Begin);
                }
            }
            //到下一个IFD的偏移量,如果这个值是'0x00000000', 则表示它是最后一个IFD 并且不在跟任何的 IFD 相连接.
            buf = new byte[4];
            rc = fs.Read(buf, 0, buf.Length);
            buf = IsIntel ? buf : buf.Reverse().ToArray();
            int NextIFDOff = BitConverter.ToInt32(buf, 0);

            return NextIFDOff;
        }

        //string[] DataFormat = new string[] { "unsigned byte", "ascii strings", "unsigned short", "unsigned long", "unsigned rational", "signed byte"
        //            , "undefined", "signed short", "signed long", "signed rational", "single float", "double float"};
        //int[] DataLen = new int[] { 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };
        object GetTagItemValue(bool IsIntel, string typeName, int typeLen, byte[] data)
        {
            object val = "";
            switch (typeName)
            {
                case "unsigned byte":
                    val = data[0];
                    break;
                case "ascii string":
                    val = Encoding.ASCII.GetString(data).Replace("\0", " ").Trim();
                    break;
                case "unsigned short":
                    data = IsIntel ? data : data.Reverse().ToArray();
                    data = data.Skip(2).ToArray();
                    val = BitConverter.ToUInt16(data, 0);
                    break;
                case "unsigned long":
                    data = IsIntel ? data : data.Reverse().ToArray();
                    val = BitConverter.ToUInt32(data, 0);
                    break;
                case "unsigned short/long":
                    {
                        //data = IsIntel ? data : data.Reverse().ToArray();
                        int baseTypeLen = data.Length / typeLen;
                        uint[] valA = new uint[typeLen];
                        for (int i = 0; i < typeLen; i++)
                        {
                            byte[] tdata = data.Skip(i * baseTypeLen).Take(baseTypeLen).ToArray();
                            if (baseTypeLen == 2)
                            {
                                byte[] td = data.Skip(i * 2).Take(2).ToArray();
                                string valHex = BitConverter.ToString(td, 0).Replace("-", "");
                                val = Convert.ToUInt16(valHex, 16);
                                valA[i] = BitConverter.ToUInt16(td, 0);
                            }
                            else if (baseTypeLen == 4)
                            {
                                byte[] td = data.Skip(i * 4).Take(4).ToArray();
                                if (td[0] == 0 && td[1] == 0)
                                { td = data.Skip(2).Take(2).ToArray(); }
                                else if (td[2] == 0 && td[3] == 0)
                                { td = data.Take(2).ToArray(); }
                                //td = IsIntel ? td : td.Reverse().ToArray();
                                string valHex = BitConverter.ToString(td, 0).Replace("-", "");
                                val = Convert.ToUInt32(valHex, 16);

                                valA[i] = uint.Parse(val.ToString());
                            }
                            val = string.Join(",", valA);
                        }

                    }
                    break;
                case "unsigned rational":
                    {
                        data = IsIntel ? data : data.Reverse().ToArray();
                        typeLen = data.Length / 4;
                        uint[] valA = new uint[typeLen];
                        for (int i = 0; i < typeLen; i++)
                        {
                            byte[] td = data.Skip(i * 4).Take(4).ToArray();
                            //td = IsIntel ? td : td.Reverse().ToArray();
                            valA[i] = BitConverter.ToUInt32(td, 0);
                        }
                        val = string.Join("/", valA);
                    }
                    break;
                case "signed byte":
                    val = data[0];
                    break;
                case "undefined":
                    val = "";
                    break;
                case "signed short":
                    data = IsIntel ? data : data.Reverse().ToArray();
                    val = BitConverter.ToUInt32(data, 0);
                    break;
                case "signed rational":
                    data = IsIntel ? data : data.Reverse().ToArray();
                    object[] da1 = new object[data.Length / 4];
                    for (int i = 0; i < da1.Length; i++) { da1[i] = i; }
                    val = string.Join("/", da1.Select(p => BitConverter.ToInt32(data.Skip((int)p * 4).Take(4).ToArray(), 0)));
                    break;
                case "single float":
                    data = IsIntel ? data : data.Reverse().ToArray();
                    val = BitConverter.ToSingle(data, 0);
                    break;
                case "double float":
                    data = IsIntel ? data : data.Reverse().ToArray();
                    val = BitConverter.ToDouble(data, 0);
                    break;
            }

            return val;
        }

        #endregion

        /// <summary>
        /// 定义量化表（Define Quantization Table）,标记代码0xFFDB
        /// </summary>
        /// <param name="fs"></param>
        /// <param name="sb"></param>
        public ITag DQT(FileStream fs)
        {
            DQT d = new ImageReader.DQT();
            d.DQTItems = new List<ImageReader.DQT.DQTItem>();

            fs.Seek(-2, SeekOrigin.Current);
            while (true)
            {
                // DQT，Define Quantization Table，定义量化表
                byte[] buf = new byte[2];
                int rc = fs.Read(buf, 0, buf.Length);
                string dqtCode = HexUtil.ToHex(buf);

                if (dqtCode != "FFDB")
                {
                    fs.Seek(-2, SeekOrigin.Current);
                    break;
                }
                else
                    d.Code = dqtCode;
                //DQT数据长度
                buf = new byte[2];
                rc = fs.Read(buf, 0, buf.Length);
                buf = buf.Reverse().ToArray();
                int dqtDataLen = BitConverter.ToUInt16(buf, 0);

                d.DataLen = dqtDataLen;
                int dqtid = 0;
                int bytesReaded = 0;
                while (dqtDataLen > 2 && bytesReaded < (dqtDataLen - 2) && dqtid < 3)
                {
                    DQT.DQTItem item = new DQT.DQTItem();
                    //量化表,数据长度-2字节,量化表数量为1~4
                    //精度及量化表ID，1字节，高4位：精度，只有两个可选值；0：8位；1：16位；低4位：量化表ID，取值范围为0～3
                    buf = new byte[1];
                    rc = fs.Read(buf, 0, buf.Length);
                    string dqtIdData = Convert.ToString(buf[0], 2).PadLeft(8, '0');
                    string jd = (buf[0] >> 4) == 0 ? "8位" : "16位";
                    item.QuantizationAccuracy = ((buf[0] >> 4) == 0 ? 8 : 16);
                    dqtid = (byte)(buf[0] << 4) >> 4;
                    //表项 (64×(精度+1))字节,例如8位精度的量化表其表项长度为64×（0+1）=64字节
                    int dqtDataBytesLen = 64 * ((jd == "8位" ? 0 : 1) + 1);
                    item.TableItemLen = dqtDataBytesLen;
                    buf = new byte[dqtDataBytesLen];
                    rc = fs.Read(buf, 0, buf.Length);
                    item.TableItemData = buf;
                    item.TableID = dqtid;

                    bytesReaded += 1;
                    bytesReaded += dqtDataBytesLen;
                    d.DQTItems.Add(item);
                }
            }
            return d;
        }
        /// <summary>
        /// 图像帧开始（Start of Frame），标记代码0xFFC0
        /// 非层次哈夫曼编码>>
        /// FFC0:基线离散余弦变换；
        /// FFC1:扩展顺序离散余弦变换；
        /// FFC2:递进离散余弦变换；
        /// FFC3:空间顺序无损；
        /// 层次哈夫曼编码>>
        /// FFC5:差分离散余弦变换；
        /// FFC6:差分层次离散余弦变换；
        /// FFC7:差分空间无损；
        /// 非层次算术编码>>
        /// FFC9:为JPEG扩展保留；
        /// FFCA:扩展顺序离散余弦变换；
        /// FFCB:递进离散余弦变换；
        /// 层次算术编码>>
        /// FCD:空间顺序无损；
        /// FFCE:差分层次离散余弦变换；
        /// FFCF:差分空间无损；
        /// </summary>
        /// <param name="fs"></param>
        /// <param name="buf"></param>
        /// <param name="sb"></param>
        public ITag SOFN(FileStream fs, byte[] buf)
        {
            SOFN s = new ImageReader.SOFN();
            s.ComponentItems = new List<ImageReader.SOFN.ComponentItem>();
            //SOF0，Start of Frame，帧图像开始,标记代码:0xFFC0
            //buf = new byte[2];
            //rc = fs.Read(buf, 0, buf.Length);
            string SOF0Code = HexUtil.ToHex(buf);
            string SOFN = SOF0Code == "FFC0" ? "SOF0" : (SOF0Code == "FFC1" ? "SOF1" : (SOF0Code == "FFC2" ? "SOF2" : SOF0Code));
            s.Code = SOF0Code;
            //数据长度
            buf = new byte[2];
            int rc = fs.Read(buf, 0, buf.Length);
            buf = buf.Reverse().ToArray();
            int SOF0DataLen = BitConverter.ToUInt16(buf, 0);
            s.DataLen = SOF0DataLen;
            //精度
            buf = new byte[1];
            rc = fs.Read(buf, 0, buf.Length);
            int SOF0JD = buf[0];
            s.Accuracy = SOF0JD;
            //图像高度
            buf = new byte[2];
            rc = fs.Read(buf, 0, buf.Length);
            buf = buf.Reverse().ToArray();
            int ImagHeight = BitConverter.ToUInt16(buf, 0);
            s.ImageHeight = ImagHeight;
            //图像宽度
            buf = new byte[2];
            rc = fs.Read(buf, 0, buf.Length);
            buf = buf.Reverse().ToArray();
            int ImagWidth = BitConverter.ToUInt16(buf, 0);
            s.ImageWidth = ImagWidth;
            //颜色分量数,1：灰度图；3：YCrCb或YIQ；4：CMYK,而JFIF中使用YCrCb，故这里颜色分量数恒为3
            buf = new byte[1];
            rc = fs.Read(buf, 0, buf.Length);
            int ColorFL = buf[0];
            s.ColorComponentType = ColorComponentTypes.YCrCb_YIQ;
            //颜色分量信息,颜色分量数×3字节（通常为9字节）
            for (int i = 0; i < ColorFL; i++)
            {
                SOFN.ComponentItem item = new ImageReader.SOFN.ComponentItem();
                int colorFLID = fs.ReadByte();
                byte exampleitem = (byte)fs.ReadByte();
                int QuantizationTb = fs.ReadByte();
                item.ID = colorFLID;
                item.QuantizationTableID = QuantizationTb;
                //水平/垂直采样因子, 高4位：水平采样因子,低4位：垂直采样因子
                item.HExamplingRatio = exampleitem >> 4; //Convert.ToInt32(Convert.ToString(exampleitem, 2).PadLeft(8, '0').Substring(0, 4).PadLeft(8, '0'), 2);
                item.VExamplingRatio = (byte)(exampleitem << 4) >> 4;// Convert.ToInt32(Convert.ToString(exampleitem, 2).PadLeft(8, '0').Substring(4, 4).PadLeft(8, '0'), 2);

                s.ComponentItems.Add(item);
            }
            return s;
        }
        /// <summary>
        /// 定义哈夫曼表（Difine Huffman Table）,标记代码0xFFC4
        /// </summary>
        /// <param name="fs"></param>
        /// <param name="sb"></param>
        public ITag DHT(FileStream fs)
        {
            bool DCFlag = false, ACFlag = false;
            DHT d = new ImageReader.DHT();
            d.ACTables = new List<ImageReader.DHT.DHTItem>(2);
            d.DCTables = new List<ImageReader.DHT.DHTItem>(2);

            fs.Seek(-2, SeekOrigin.Current);
            while (true)
            {
                //DHT，Difine Huffman Table，定义哈夫曼表
                byte[] buf = new byte[2];
                int rc = fs.Read(buf, 0, buf.Length);
                string DHTCode = HexUtil.ToHex(buf);
                if (DHTCode == "FFC4")
                    d.Code = DHTCode;
                else
                {
                    fs.Seek(-2, SeekOrigin.Current);
                    break;
                }
                //数据长度
                buf = new byte[2];
                rc = fs.Read(buf, 0, buf.Length);
                buf = buf.Reverse().ToArray();
                int DHTDataLen = BitConverter.ToUInt16(buf, 0);
                d.DataLen = DHTDataLen;

                int dhtid = 0;
                int bytesReaded = 0;

                while (DHTDataLen > 2 && bytesReaded < (DHTDataLen - 2) && dhtid < 3)
                {
                    DHT.DHTItem item = new ImageReader.DHT.DHTItem();
                    //表ID和表类型,高4位：类型，只有两个值可选,0：DC直流；1：AC交流,低4位：哈夫曼表ID，DC表和AC表分开编码
                    int HTIdType = fs.ReadByte();
                    string HTIdTypeStr = Convert.ToString(HTIdType, 2).PadLeft(8, '0');
                    string httype = HTIdTypeStr.StartsWith("0000") ? "DC直流" : "AC交流";
                    int htid = Convert.ToUInt16("0000" + HTIdTypeStr.Substring(4, 4), 2);
                    item.HuffmanTableType = HTIdTypeStr.StartsWith("0000") ? HuffmanTableTypes.DC直流 : HuffmanTableTypes.AC交流;
                    item.TableID = htid;
                    //不同位数的码字数量16字节
                    buf = new byte[16];
                    rc = fs.Read(buf, 0, buf.Length);
                    item.HuffmanChainCodes = buf;
                    int leafNum = buf.Sum(p => p);
                    item.HuffmanChainNum = leafNum;
                    //叶子结点按码字数量从小到大排列
                    buf = new byte[leafNum];
                    rc = fs.Read(buf, 0, buf.Length);
                    item.HuffmanNodeWeight = buf;

                    if (item.HuffmanTableType == HuffmanTableTypes.DC直流)
                    {
                        if (DCFlag)
                        { d.DHT_DC1 = item; }
                        else
                        { d.DHT_DC0 = item; }

                        d.DCTables.Add(item);
                    }
                    else
                    {
                        if (ACFlag)
                        { d.DHT_AC1 = item; }
                        else
                        { d.DHT_AC0 = item; }

                        d.ACTables.Add(item);
                    }
                    DCFlag = (DCFlag || item.HuffmanTableType == HuffmanTableTypes.DC直流) ? true : false;
                    ACFlag = (ACFlag || item.HuffmanTableType == HuffmanTableTypes.AC交流) ? true : false;
                    bytesReaded += 1;
                    bytesReaded += 16;
                    bytesReaded += leafNum;

                    if ((DHTDataLen - 2 - 1 - 16) == leafNum)
                    { break; }
                }
            }
            return d;
        }
        /// <summary>
        /// 定义差分编码累计复位的间隔（Define Restart Interval）,标记代码0xFFDD
        /// </summary>
        /// <param name="fs"></param>
        /// <param name="buf"></param>
        /// <param name="sb"></param>
        public ITag DRI(FileStream fs, byte[] buf)
        {
            DRI d = new ImageReader.DRI();
            string DRICode = HexUtil.ToHex(buf);
            d.Code = DRICode;
            //数据长度
            buf = new byte[2];
            int rc = fs.Read(buf, 0, buf.Length);
            buf = buf.Reverse().ToArray();
            int DRIDataLen = BitConverter.ToUInt16(buf, 0);
            d.DataLen = DRIDataLen;
            buf = new byte[2];
            rc = fs.Read(buf, 0, buf.Length);
            buf = buf.Reverse().ToArray();
            int MCUMargin = BitConverter.ToUInt16(buf, 0);
            d.RSTInterval = MCUMargin;
            return d;
        }
        /// <summary>
        /// 扫描开始（Start of Scan）,12字节,标记代码0xFFC4
        /// </summary>
        /// <param name="fs"></param>
        /// <param name="buf"></param>
        public ITag SOS(FileStream fs, byte[] buf)
        {
            SOS s = new ImageReader.SOS();
            s.SOSColorComponents = new List<ImageReader.SOS.SOSColorComponentItem>();

            //SOS，Start of Scan，扫描开始 12字节
            string SOSCode = HexUtil.ToHex(buf);
            s.Code = SOSCode;
            //数据长度
            buf = new byte[2];
            int rc = fs.Read(buf, 0, buf.Length);
            buf = buf.Reverse().ToArray();
            int SOSDataLen = BitConverter.ToUInt16(buf, 0);
            s.DataLen = SOSDataLen;
            //颜色分量数,1：灰度图；3：YCrCb或YIQ；4：CMYK,而JFIF中使用YCrCb，故这里颜色分量数恒为3
            int SOSColorFL = fs.ReadByte();
            s.ColorComponentType = ColorComponentTypes.YCrCb_YIQ;
            //颜色分量信息,颜色分量数×3字节（通常为9字节）
            for (int i = 0; i < SOSColorFL; i++)
            {
                SOS.SOSColorComponentItem item = new SOS.SOSColorComponentItem();
                int colorFLID = fs.ReadByte();
                byte exampleitem = (byte)fs.ReadByte();
                string exampleitemStr = Convert.ToString(exampleitem, 2).PadLeft(8, '0');
                item.ColorComponentID = colorFLID;
                //直流/交流系数表号 
                item.DCTableID = exampleitem >> 4;// Convert.ToUInt16("0000" + exampleitemStr.Substring(0, 4), 2);
                item.ACTableID = (byte)(exampleitem << 4) >> 4;// Convert.ToUInt16("0000" + exampleitemStr.Substring(4, 4), 2);
                s.SOSColorComponents.Add(item);
            }
            //压缩图像数据
            //buf = new byte[3];
            //rc = fs.Read(buf, 0, buf.Length);
            //谱选择开始,0x00
            s.PSelectStart = fs.ReadByte();
            //谱选择结束,0x3F
            s.PSelectEnd = fs.ReadByte();
            //谱选择,0x00
            s.PSelect = fs.ReadByte();
            //第一个MCU字节，在文件流中的位置
            s.MCUDataStartFilePosition = fs.Position;
            return s;
        }
        /// <summary>
        /// 注释，标记代码0xFFFE
        /// </summary>
        public ITag COM(FileStream fs)
        {
            //数据长度
            byte[] buf = new byte[2];
            int rc = fs.Read(buf, 0, buf.Length);
            buf = buf.Reverse().ToArray();
            int COMDataLen = BitConverter.ToUInt16(buf, 0);
            if (COMDataLen > 0)
            {
                buf = new byte[COMDataLen - 2];
                rc = fs.Read(buf, 0, buf.Length);
                string com = Encoding.ASCII.GetString(buf);
            }
            return null;
        }

        #endregion

        private byte[] MCUBitmapBytes = null;
        public byte[] GetMCUBytes(bool Include = true)
        {
            List<byte[]> MCU = ReadMCU(Include);

            if (!Include)
            { return null; }

            int Hmax = sof.ComponentItems[0].HExamplingRatio;
            int Vmax = sof.ComponentItems[0].VExamplingRatio;
            int mapW = Hmax * 8;
            int mapH = Vmax * 8;

            Bitmap map = null;
            map = new Bitmap(mapW, mapH, PixelFormat.Format24bppRgb);
            int copyIdx = 0;

            #region

            if (this.MCUBitmapBytes == null)
            { MCUBitmapBytes = new byte[mapW * mapH * 3]; }

            for (int i = 0; i < Vmax; i++)
            {
                for (int l = 0; l < 8; l++)//DU
                {
                    for (int j = 0; j < Hmax; j++)
                    {
                        Array.Copy(MCU[i * Hmax + j], l * 24, MCUBitmapBytes, copyIdx, 24);
                        copyIdx += 24;
                    }
                }
            }

            #endregion

            return this.MCUBitmapBytes;
        }

        //记录三个颜色分量的DC值
        int[] DCdiff = new int[3] { 0, 0, 0 };
        static int CacheLen = 1600;
        char[] ImageBitsData = new char[CacheLen];//200字节
        int BitsDataLen = 0;
        int BitsDataIdx = -1;
        byte PrevByte = 0;//记录读取的上一个字节
        int RSTnIdx { get; set; }
        bool EOF { get; set; }//是否已经到达图片文件的末尾

        private List<string> SOFNCodes = new List<string>() { "FFC0", "FFC1", "FFC2", "FFC3", "FFC5", "FFC6", "FFC7", "FFC9", "FFCA", "FFCB", "FFCD", "FFCE", "FFCF" };
        private List<string> SOFNNames = new List<string>() { "基线离散余弦变换", "扩展顺序离散余弦变换", "递进离散余弦变换", "空间顺序无损", "差分离散余弦变换"
            , "差分层次离散余弦变换", "差分空间无损", "为JPEG扩展保留", "扩展顺序离散余弦变换", "递进离散余弦变换", "空间顺序无损", "差分层次离散余弦变换", "差分空间无损" };


        Dictionary<long, int> DCHuffmanTreeDic = null;
        Dictionary<long, int> ACHuffmanTreeDic = null;
        List<string> DCHuffmanTreeList = null;
        List<string> ACHuffmanTreeList = null;
        byte[] DCHuffmanTreeWgt = null;
        byte[] ACHuffmanTreeWgt = null;
        /// <summary>
        /// 解码一个MCU并从YCrCb转为RGB
        /// </summary>
        /// <returns></returns>
        public List<byte[]> ReadMCU(bool Include = true)
        {
            if (sof.Code != "FFC0")
            { throw new Exception("不支持：" + SOFNNames[SOFNCodes.IndexOf(sof.Code)]); }

            int Comp0Cnt = sof.ComponentItems[0].HExamplingRatio * sof.ComponentItems[0].VExamplingRatio;//Y分量数据单元数
            int Comp1Cnt = sof.ComponentItems[1].HExamplingRatio * sof.ComponentItems[1].VExamplingRatio;//Cr分量数据单元数
            int Comp2Cnt = sof.ComponentItems[2].HExamplingRatio * sof.ComponentItems[2].VExamplingRatio;//Cb分量数据单元数
            int MCUCompCnt = Comp0Cnt + Comp1Cnt + Comp2Cnt;//一个MCU内数据单元数

            //存放一个MCU所有的DU数组
            float[][] MCU = new float[MCUCompCnt][];
            //Y分量
            DCHuffmanTreeDic = dht.DCTables[sos.SOSColorComponents[0].DCTableID].HuffmanTreeDic;
            ACHuffmanTreeDic = dht.ACTables[sos.SOSColorComponents[0].ACTableID].HuffmanTreeDic;
            DCHuffmanTreeList = dht.DCTables[sos.SOSColorComponents[0].DCTableID].HuffmanTree;
            ACHuffmanTreeList = dht.ACTables[sos.SOSColorComponents[0].ACTableID].HuffmanTree;
            DCHuffmanTreeWgt = dht.DCTables[sos.SOSColorComponents[0].DCTableID].HuffmanNodeWeight;
            ACHuffmanTreeWgt = dht.ACTables[sos.SOSColorComponents[0].ACTableID].HuffmanNodeWeight;

            for (int i = 0; i < Comp0Cnt; i++)
            { MCU[i] = ReadDU(0, Include); }
            //Cr分量
            DCHuffmanTreeDic = dht.DCTables[sos.SOSColorComponents[1].DCTableID].HuffmanTreeDic;
            ACHuffmanTreeDic = dht.ACTables[sos.SOSColorComponents[1].ACTableID].HuffmanTreeDic;
            DCHuffmanTreeList = dht.DCTables[sos.SOSColorComponents[1].DCTableID].HuffmanTree;
            ACHuffmanTreeList = dht.ACTables[sos.SOSColorComponents[1].ACTableID].HuffmanTree;
            DCHuffmanTreeWgt = dht.DCTables[sos.SOSColorComponents[1].DCTableID].HuffmanNodeWeight;
            ACHuffmanTreeWgt = dht.ACTables[sos.SOSColorComponents[1].ACTableID].HuffmanNodeWeight;

            for (int i = 0; i < Comp1Cnt; i++)
            { MCU[Comp0Cnt + i] = ReadDU(1, Include); }
            //Cb分量
            DCHuffmanTreeDic = dht.DCTables[sos.SOSColorComponents[2].DCTableID].HuffmanTreeDic;
            ACHuffmanTreeDic = dht.ACTables[sos.SOSColorComponents[2].ACTableID].HuffmanTreeDic;
            DCHuffmanTreeList = dht.DCTables[sos.SOSColorComponents[2].DCTableID].HuffmanTree;
            ACHuffmanTreeList = dht.ACTables[sos.SOSColorComponents[2].ACTableID].HuffmanTree;
            DCHuffmanTreeWgt = dht.DCTables[sos.SOSColorComponents[2].DCTableID].HuffmanNodeWeight;
            ACHuffmanTreeWgt = dht.ACTables[sos.SOSColorComponents[2].ACTableID].HuffmanNodeWeight;

            for (int i = 0; i < Comp2Cnt; i++)
            { MCU[Comp0Cnt + Comp1Cnt + i] = ReadDU(2, Include); }

            if (!Include)
            { return null; }


            List<byte[]> colorList = new List<byte[]>();
            //YCrCb转RGB
            for (int id = 0; id < Comp0Cnt; id++)
            {
                byte[] colorM = new byte[64 * 3];
                for (int mi = 0; mi < MCU[id].Length; mi++)
                {
                    int CIdx = ((id % 2) == 0 ? 0 : 4) + (id / 2) * 8 * 4 + mi / 8 / 2 * 8 + ((mi / 2) % 4);
                    double Y = this.ShowY ? MCU[id][mi] + 128 : 0;
                    double Cr = this.ShowCr ? MCU[MCUCompCnt - 2][CIdx] : 0;
                    double Cb = this.ShowCb ? MCU[MCUCompCnt - 1][CIdx] : 0;

                    double R = Y + 1.402 * Cb; //R = Y + 1.402 * Cb + 128
                    double G = Y - 0.34414 * Cr - 0.71414 * Cb;//G = Y - 0.34414 * Cr - 0.71414 * Cb + 128
                    double B = Y + 1.772 * Cr;//B = Y + 1.772 * Cb + 128

                    R = R > 255 ? 255 : (R < 0 ? 0 : R);
                    G = G > 255 ? 255 : (G < 0 ? 0 : G);
                    B = B > 255 ? 255 : (B < 0 ? 0 : B);

                    colorM[mi * 3] = (byte)B;
                    colorM[mi * 3 + 1] = (byte)G;
                    colorM[mi * 3 + 2] = (byte)R;
                }
                colorList.Add(colorM);
            }

            return colorList;
        }

        long HuffCodeLongVal { get; set; }

        /// <summary>
        /// 解码一个数据单元
        /// </summary>
        /// <param name="CompIndex"></param>
        /// <returns></returns>
        public float[] ReadDU(int CompIndex, bool Include = true)
        {
            float[] DU = Include ? new float[64] : new float[1];
            int DUIdx = 0;
            this.HuffCodeLongVal = 0;

            while (DUIdx < 64)
            {
                int HfIdx = -1;
                Dictionary<long, int> HuffmanTreeDic = DUIdx == 0 ? DCHuffmanTreeDic : ACHuffmanTreeDic;
                List<string> HuffmanTreeList = DUIdx == 0 ? DCHuffmanTreeList : ACHuffmanTreeList;
                int ShortestCodelen = HuffmanTreeList.First().Length;
                int MaxCodeLen = HuffmanTreeList.Last().Length;

                StartDeHufff:
                {
                    this.HuffCodeLongVal = 0;
                    for (int ci = 0; ci < MaxCodeLen; ci++)//一个哈夫曼编码的最大长度为16位
                    {
                        if ((this.BitsDataIdx + 1) >= this.BitsDataLen)
                        {
                            if (this.RSTnIdx >= 0)
                            {
                                this.PrepareBitsdata();
                                goto StartDeHufff;
                            }
                            else
                            {
                                this.PrepareBitsdata();
                                if (this.BitsDataLen == 0)
                                { break; }
                            }
                        }
                        //进行一次哈夫曼编码查询
                        this.BitsDataIdx++;
                        byte BitVal = (byte)(this.ImageBitsData[this.BitsDataIdx] - 48);
                        this.HuffCodeLongVal = this.HuffCodeLongVal * 10 + BitVal;

                        if (ci >= ShortestCodelen - 1)
                        {
                            if (HuffmanTreeDic.ContainsKey(this.HuffCodeLongVal))
                            {
                                HfIdx = HuffmanTreeDic[this.HuffCodeLongVal];
                                if (HuffmanTreeList[HfIdx].Length != ci + 1)
                                { HfIdx = -1; }
                            }
                            if (HfIdx >= 0)
                            { break; }
                        }
                    }
                }

                if (HfIdx == -1)
                {
                    if (this.EOF)
                    { break; }
                    goto StartDeHufff;
                }
                //权值表
                byte[] HuffmanTreeWgt = DUIdx == 0 ? DCHuffmanTreeWgt : ACHuffmanTreeWgt;
                //获取对应权值
                byte wgt = HuffmanTreeWgt[HfIdx];
                if (wgt == 0)//权值为0说明一个DU结束
                {
                    if (DUIdx == 0)
                    {
                        if (Include)
                        { DU[DUIdx] = DCdiff[CompIndex]; }
                        DUIdx++;
                        continue;
                    }
                    else
                    { break; }
                }
                int readNum = wgt;//需要读取的位数
                if (DUIdx > 0)
                {
                    if (wgt == 0xF0)
                    {
                        DUIdx += 16;
                        continue;
                    }
                    else
                    {
                        DUIdx += wgt >> 4;//RLC编码中连续0的个数
                        readNum = wgt & 0x0F;//连续0后面的非0数据位数
                    }
                }
                if (readNum == 0)
                { continue; }
                //准备需要读取的位
                this.PrepareBitsdata();
                //读取位
                string ADCStrVal = "";
                if (this.BitsDataLen - this.BitsDataIdx - 1 < readNum)
                {
                    int treadNum = this.BitsDataLen - this.BitsDataIdx - 1;
                    ADCStrVal = new string(this.ImageBitsData, this.BitsDataIdx + 1, treadNum);
                    this.BitsDataIdx += treadNum;
                    this.PrepareBitsdata();
                    treadNum = readNum - treadNum;
                    ADCStrVal += new string(this.ImageBitsData, 0, treadNum);
                    this.BitsDataIdx += treadNum;
                }
                else
                {
                    ADCStrVal = new string(this.ImageBitsData, this.BitsDataIdx + 1, readNum);
                    this.BitsDataIdx += readNum;
                }

                if (ADCStrVal.Length == 0)
                { break; }

                if (DUIdx > 63)
                { break; }

                int ADCIntVal = 0;
                if (ADCStrVal.StartsWith("0"))
                {
                    if (ADCStrVal.Length < 16)
                    {
                        UInt16 dd = Convert.ToUInt16(ADCStrVal.PadLeft(16, '1'), 2);
                        ADCIntVal = -(ushort)~dd;
                    }
                    else
                    {
                        //使用字符取反的方式（效率较低）
                        ADCStrVal = ImageTool.StringBitReverse(ADCStrVal);
                        ADCIntVal = -Convert.ToInt32(ADCStrVal, 2);
                    }
                }
                else
                { ADCIntVal = Convert.ToInt32(ADCStrVal, 2); }

                if (DUIdx == 0)//DC直接转化
                {
                    ADCIntVal += DCdiff[CompIndex];
                    DCdiff[CompIndex] = ADCIntVal;//纪录DC值供下一个DC解码时使用,如果遇到RSTn则重新初始化为0
                }
                if (Include)
                { DU[DUIdx] = ADCIntVal; }
                DUIdx++;
                this.HuffCodeLongVal = 0;
            }

            if (!Include)
            { return DU; }

            if ((CompIndex == 0 && this.ShowY) || (CompIndex == 1 && this.ShowCr) || (CompIndex == 2 && this.ShowCb))
            {
                byte[] DQTb = null;
                try
                { DQTb = dqt.DQTItems[sof.ComponentItems[CompIndex].QuantizationTableID].TableItemData; }
                catch (Exception ex)
                {
                    if (dqt.DQTItems.Count == 1)
                    { DQTb = dqt.DQTItems[0].TableItemData; }
                    else
                    { throw ex; }
                }

                for (int i = 0; i < DU.Length; i++)
                {
                    DU[i] *= DQTb[i];//反量化
                }

                //反Zig-zag编码
                DU = ZigZag2(DU);
                JpegReader.IDCT(ref DU);
            }

            return DU;
        }
        /// <summary>
        /// RSTn计数
        /// </summary>
        int RSTnCnt { get; set; }
        /// <summary>
        /// 读取一定字节的图像数据并以二进制的形式存到缓存队列
        /// </summary>
        public void PrepareBitsdata()
        {
            if ((this.BitsDataIdx + 1) == this.BitsDataLen && this.RSTnIdx >= 0)
            {
                this.DCdiff = new int[3];
                this.RSTnCnt++;
                this.RSTnIdx = -1;
            }

            if (((this.BitsDataIdx + 1) == this.BitsDataLen) && this.RSTnIdx == -1)
            {
                this.BitsDataIdx = -1;
                this.BitsDataLen = 0;
                int BytesRead = JpegReader.CacheLen / 8;
                try
                {
                    for (int br = 0; br < BytesRead; br++)
                    {
                        byte retByte = GetMCUByteFromFile(ref PrevByte);
                        if (PrevByte == 255)
                        {
                            if (retByte >= 208 && retByte <= 216)//RSTn
                            {
                                this.RSTnIdx = retByte - 208;
                                break;
                            }
                            else if (retByte == 217)//图像结束
                            { break; }
                        }
                        Convert.ToString(retByte, 2).PadLeft(8, '0').ToArray().CopyTo(this.ImageBitsData, this.BitsDataLen);
                        this.BitsDataLen += 8;
                    }
                }
                catch (Exception ex)
                { }
            }
        }

        /// <summary>
        /// 获取一个字节的图像数据
        /// </summary>
        /// <param name="buf"></param>
        /// <param name="PrevByte"></param>
        /// <returns></returns>
        public byte GetMCUByteFromFile(ref byte PrevByte)
        {
            if (this.EOF)
            { throw new Exception("已到达文件的最后一个字节"); }

            try
            {
                byte retByte = 0;
                Start:
                //if (buf.Count > 0)
                {
                    PrevByte = (byte)FS.ReadByte();
                    if (PrevByte == 255 && !this.EOF)
                    {
                        retByte = (byte)FS.ReadByte();
                        if (retByte == 0)//图像数据中0xFF的后缀0x00，需要去掉
                        { retByte = 255; }//0xFF00填充
                        else if (retByte == 217)
                        { }//0xFFD9图像结束
                        else if (retByte >= 208 && retByte <= 215)
                        { }//RSTn标记0xFF" + Convert.ToString(buf[i], 16));
                        else if (retByte == 255)
                        { goto Start; }//忽略当前0xFF，对后一个0xFF再作判断
                        else
                        { goto Start; }
                    }
                    else
                    { retByte = PrevByte; }
                }

                return retByte;
            }
            catch (Exception ex)
            {
                if (FS.Position >= FS.Length)
                {
                    this.EOF = true;
                    throw new Exception("已到达文件的最后一个字节");
                }
                else
                { throw ex; }
            }
        }

        public double[] ZigZag(double[] ser)
        {
            if (ser.Length != 64)
            { throw new Exception("序列长度必须为64"); }

            double[] matrix = new double[64];
            bool dir_x = false, dir_y = true;
            int x = 1, y = 0;//x,y坐标参照Windows GDI+标准坐标系（左上为0，0）
            int idx = 2;//从源序列的第三个元素开始z编码
            matrix[0] = ser[0];
            matrix[1] = ser[1];
            while (true)
            {
                x += dir_x ? 1 : -1;
                y += dir_y ? 1 : -1;

                if (x < 0 && y <= 7)//左中
                {
                    x = x < 0 ? 0 : x;
                    dir_x = dir_x ? false : true;
                    dir_y = dir_y ? false : true;
                }
                else if (x < 0 && y > 7)//左下角
                {
                    x = 1;
                    y = 7;
                    dir_x = dir_x ? false : true;
                    dir_y = dir_y ? false : true;
                }
                else if (x <= 7 && y < 0)//上中
                {
                    y = y < 0 ? 0 : x;
                    dir_x = dir_x ? false : true;
                    dir_y = dir_y ? false : true;
                }
                else if (x > 7 && y < 7)//右中
                {
                    x = 7;
                    y += 2;
                    dir_x = dir_x ? false : true;
                    dir_y = dir_y ? false : true;
                }
                else if (x < 7 && y > 7)//下中
                {
                    x += 2;
                    y = 7;
                    dir_x = dir_x ? false : true;
                    dir_y = dir_y ? false : true;
                }

                matrix[y * 8 + x] = ser[idx];
                idx++;

                if (x == 7 && y == 7)
                { break; }
            }

            return matrix;
        }


        short[] ZZ = new short[64]
            {0  ,1  ,5  ,6  ,14 ,15 ,27 ,28 ,2  ,4  ,7  ,13 ,16 ,26 ,29 ,42 ,3  ,8  ,12 ,17 ,25 ,30 ,41 ,43 ,9  ,11 ,18 ,24 ,31 ,40 ,44 ,53 ,10 ,19 ,23 ,32 ,39 ,45 ,52 ,54 ,20 ,22 ,33 ,38 ,46 ,51 ,55 ,60 ,21 ,34 ,37 ,47 ,50 ,56 ,59 ,61 ,35 ,36 ,48 ,49 ,57 ,58 ,62 ,63};
        public float[] ZigZag2(float[] ser)
        {
            float[] temp = new float[64];
            for (int i = 0; i < 64; i++)
            { temp[i] = ser[ZZ[i]]; }

            return temp;
        }

        public float[] IZigZag(float[] ser)
        {
            float[] temp = new float[64];
            for (int i = 0; i < 64; i++)
            { temp[ZZ[i]] = ser[i]; }

            return temp;
        }

        #region [DCT]

        public static float[] DCT(float[] block, int MtxW = 8)
        {
            //偶余弦变换EDCT 
            float[] tmpBlock = new float[block.Length];
            short i, j, p, q;
            int N = MtxW;
            float PI = 3.14159262F;
            float coefficient1, coefficient2;
            for (p = 0; p < N; p++)
            {
                for (q = 0; q < N; q++)
                {
                    if (p == 0) coefficient1 = (float)Math.Sqrt(1.0 / N);
                    else coefficient1 = (float)Math.Sqrt(2.0 / N);
                    if (q == 0) coefficient2 = (float)Math.Sqrt(1.0 / N);
                    else coefficient2 = (float)Math.Sqrt(2.0 / N);
                    float tmp = 0.0F;
                    for (i = 0; i < N; i++)
                    {
                        for (j = 0; j < N; j++)
                        {
                            int blockIdx = i * N + j;
                            tmp += block[blockIdx] * (float)Math.Cos((2 * i + 1) * PI * p / (2 * N)) * (float)Math.Cos((2 * j + 1) * PI * q / (2 * N));//形成新的矩阵 
                        }
                    }
                    tmpBlock[p * N + q] = (float)Math.Round(coefficient1 * coefficient2 * tmp);
                }
            }

            return tmpBlock;
        }
        public static void DCT(float[,] input, float[,] output, int MtxW = 8)
        {
            //偶余弦变换EDCT 
            int N = MtxW;
            float PI = 3.14159262F;
            short i, j, p, q;
            double coefficient1, coefficient2;
            for (p = 0; p < N; p++)
            {
                for (q = 0; q < N; q++)
                {
                    if (p == 0) coefficient1 = Math.Sqrt(1.0 / N);
                    else coefficient1 = Math.Sqrt(2.0 / N);
                    if (q == 0) coefficient2 = Math.Sqrt(1.0 / N);
                    else coefficient2 = Math.Sqrt(2.0 / N);
                    double tmp = 0.0;
                    for (i = 0; i < N; i++)
                    {
                        for (j = 0; j < N; j++)
                        {
                            tmp += input[i, j] * Math.Cos((2 * i + 1) * PI * p / (2 * N)) * Math.Cos((2 * j + 1) * PI * q / (2 * N));//形成新的矩阵 
                        }
                    }
                    output[p, q] = (float)Math.Round(coefficient1 * coefficient2 * tmp);
                }
            }
        }
        #endregion

        #region IDCT1
        static float C1 = 0.9808F;
        static float C2 = 0.9239F;
        static float C3 = 0.8315F;
        static float C4 = 0.7071F;
        static float C5 = 0.5556F;
        static float C6 = 0.3827F;
        static float C7 = 0.1951F;
        public static void IDCTRow(ref float[] blk, int idx)
        {
            float[] tmp = new float[16];
            idx = idx * 8;
            //first step
            tmp[0] = blk[idx + 0] * C4 + blk[idx + 2] * C2;
            tmp[1] = blk[idx + 4] * C4 + blk[idx + 6] * C6;
            tmp[2] = blk[idx + 0] * C4 + blk[idx + 2] * C6;
            tmp[3] = -blk[idx + 4] * C4 - blk[idx + 6] * C2;
            tmp[4] = blk[idx + 0] * C4 - blk[idx + 2] * C6;
            tmp[5] = -blk[idx + 4] * C4 + blk[idx + 6] * C2;
            tmp[6] = blk[idx + 0] * C4 - blk[idx + 2] * C2;
            tmp[7] = blk[idx + 4] * C4 - blk[idx + 6] * C6;

            tmp[8] = blk[idx + 1] * C7 - blk[idx + 3] * C5;
            tmp[9] = blk[idx + 5] * C3 - blk[idx + 7] * C1;
            tmp[10] = blk[idx + 1] * C5 - blk[idx + 3] * C1;
            tmp[11] = blk[idx + 5] * C7 + blk[idx + 7] * C3;
            tmp[12] = blk[idx + 1] * C3 - blk[idx + 3] * C7;
            tmp[13] = -blk[idx + 5] * C1 - blk[idx + 7] * C5;
            tmp[14] = blk[idx + 1] * C1 + blk[idx + 3] * C3;
            tmp[15] = blk[idx + 5] * C5 + blk[idx + 7] * C7;
            //second step
            tmp[0] = 0.5F * (tmp[0] + tmp[1]);
            tmp[1] = 0.5F * (tmp[2] + tmp[3]);
            tmp[2] = 0.5F * (tmp[4] + tmp[5]);
            tmp[3] = 0.5F * (tmp[6] + tmp[7]);
            tmp[4] = 0.5F * (tmp[8] + tmp[9]);
            tmp[5] = 0.5F * (tmp[10] + tmp[11]);
            tmp[6] = 0.5F * (tmp[12] + tmp[13]);
            tmp[7] = 0.5F * (tmp[14] + tmp[15]);

            //third step
            blk[idx + 0] = tmp[0] + tmp[7];
            blk[idx + 1] = tmp[1] + tmp[6];
            blk[idx + 2] = tmp[2] + tmp[5];
            blk[idx + 3] = tmp[3] + tmp[4];
            blk[idx + 4] = tmp[3] - tmp[4];
            blk[idx + 5] = tmp[2] - tmp[5];
            blk[idx + 6] = tmp[1] - tmp[6];
            blk[idx + 7] = tmp[0] - tmp[7];
        }

        public static void IDCTCol(ref float[] blk, int idx)
        {
            float[] tmp = new float[16];

            //first step
            tmp[0] = blk[idx + 0 * 8] * C4 + blk[idx + 2 * 8] * C2;
            tmp[1] = blk[idx + 4 * 8] * C4 + blk[idx + 6 * 8] * C6;
            tmp[2] = blk[idx + 0 * 8] * C4 + blk[idx + 2 * 8] * C6;
            tmp[3] = -blk[idx + 4 * 8] * C4 - blk[idx + 6 * 8] * C2;
            tmp[4] = blk[idx + 0 * 8] * C4 - blk[idx + 2 * 8] * C6;
            tmp[5] = -blk[idx + 4 * 8] * C4 + blk[idx + 6 * 8] * C2;
            tmp[6] = blk[idx + 0 * 8] * C4 - blk[idx + 2 * 8] * C2;
            tmp[7] = blk[idx + 4 * 8] * C4 - blk[idx + 6 * 8] * C6;

            tmp[8] = blk[idx + 1 * 8] * C7 - blk[idx + 3 * 8] * C5;
            tmp[9] = blk[idx + 5 * 8] * C3 - blk[idx + 7 * 8] * C1;
            tmp[10] = blk[idx + 1 * 8] * C5 - blk[idx + 3 * 8] * C1;
            tmp[11] = blk[idx + 5 * 8] * C7 + blk[idx + 7 * 8] * C3;
            tmp[12] = blk[idx + 1 * 8] * C3 - blk[idx + 3 * 8] * C7;
            tmp[13] = -blk[idx + 5 * 8] * C1 - blk[idx + 7 * 8] * C5;
            tmp[14] = blk[idx + 1 * 8] * C1 + blk[idx + 3 * 8] * C3;
            tmp[15] = blk[idx + 5 * 8] * C5 + blk[idx + 7 * 8] * C7;
            //second step
            tmp[0] = 0.5F * (tmp[0] + tmp[1]);
            tmp[1] = 0.5F * (tmp[2] + tmp[3]);
            tmp[2] = 0.5F * (tmp[4] + tmp[5]);
            tmp[3] = 0.5F * (tmp[6] + tmp[7]);
            tmp[4] = 0.5F * (tmp[8] + tmp[9]);
            tmp[5] = 0.5F * (tmp[10] + tmp[11]);
            tmp[6] = 0.5F * (tmp[12] + tmp[13]);
            tmp[7] = 0.5F * (tmp[14] + tmp[15]);
            //third step
            blk[idx + 0 * 8] = tmp[0] + tmp[7];
            blk[idx + 1 * 8] = tmp[1] + tmp[6];
            blk[idx + 2 * 8] = tmp[2] + tmp[5];
            blk[idx + 3 * 8] = tmp[3] + tmp[4];
            blk[idx + 4 * 8] = tmp[3] - tmp[4];
            blk[idx + 5 * 8] = tmp[2] - tmp[5];
            blk[idx + 6 * 8] = tmp[1] - tmp[6];
            blk[idx + 7 * 8] = tmp[0] - tmp[7];
        }

        public static void IDCT(ref float[] block)
        {
            for (int i = 0; i < 8; i++)
            { IDCTRow(ref block, i); }

            for (int i = 0; i < 8; i++)
            { IDCTCol(ref block, i); }
        }
        #endregion

        #region IDCT2
        public static float[] IDCT2(float[] block, int MtxW = 8)
        {
            float[] tmpBlock = new float[block.Length];
            int N = MtxW;
            float PI = 3.14159262F;
            //PI = Math.PI;
            short i, j, p, q;
            double coefficient1, coefficient2;
            for (i = 0; i < N; i++)
            {
                for (j = 0; j < N; j++)
                {
                    double tmp = 0.0;
                    for (p = 0; p < N; p++)
                    {
                        for (q = 0; q < N; q++)
                        {
                            if (p == 0) coefficient1 = Math.Sqrt(1.0 / N);
                            else coefficient1 = Math.Sqrt(2.0 / N);
                            if (q == 0) coefficient2 = Math.Sqrt(1.0 / N);
                            else coefficient2 = Math.Sqrt(2.0 / N);
                            int blockIdx = p * N + q;
                            tmp += coefficient1 * coefficient2 * block[blockIdx] * Math.Cos((2 * i + 1) * PI * p / (2 * N)) * Math.Cos((2 * j + 1) * PI * q / (2 * N));
                        }
                    }
                    tmpBlock[i * N + j] = (float)Math.Round(tmp);
                }
            }

            return tmpBlock;
        }

        public static void IDCT(float[,] input, float[,] output, int MtxW = 8)
        {
            int N = MtxW;
            float PI = 3.14159262F;
            //PI = Math.PI;
            short i, j, p, q;
            double coefficient1, coefficient2;
            for (i = 0; i < N; i++)
            {
                for (j = 0; j < N; j++)
                {
                    double tmp = 0.0;
                    for (p = 0; p < N; p++)
                    {
                        for (q = 0; q < N; q++)
                        {
                            if (p == 0) coefficient1 = Math.Sqrt(1.0 / N);
                            else coefficient1 = Math.Sqrt(2.0 / N);
                            if (q == 0) coefficient2 = Math.Sqrt(1.0 / N);
                            else coefficient2 = Math.Sqrt(2.0 / N);
                            tmp += coefficient1 * coefficient2 * input[p, q] * Math.Cos((2 * i + 1) * PI * p / (2 * N)) * Math.Cos((2 * j + 1) * PI * q / (2 * N));
                        }
                    }
                    output[i, j] = (float)Math.Round(tmp);
                }
            }
        }

        #endregion
    }
}
